package com.talkyun.openx.server.impl;

import com.talkyun.openx.OpenxSetting;
import com.talkyun.openx.server.core.Interceptor;
import com.talkyun.openx.server.core.ServiceFactory;
import com.talkyun.openx.server.core.ServiceRequest;
import com.talkyun.openx.server.core.ServiceResponse;
import com.talkyun.openx.server.core.ServiceResponse.Status;
import com.talkyun.utils.json.JSON;

import java.lang.reflect.Method;
import java.util.List;

import static com.talkyun.openx.server.core.ServiceResponse.Status.ERROR;
import static com.talkyun.openx.server.core.ServiceResponse.Status.NORMAL;
import static com.talkyun.utils.Reflector.getInterface;
import static com.talkyun.utils.Reflector.getMethod;

public class FastJsonInvoker extends AbstractInvoker {
    private ServiceFactory factory;

    public FastJsonInvoker(ServiceFactory factory) {
        this.factory = factory;
    }

    @Override
    protected List<Interceptor> getInterceptor(String mapping) {
        return factory.getInterceptor(mapping);
    }

    @Override
    public ServiceResponse doInvoke(ServiceRequest sr) throws Throwable {
        String mapping = sr.getMapping();
        Object service = factory.getService(mapping);

        if (service == null) {
            return wrap(sr.getSession(), ERROR, "Can't find " + mapping);
        } else {
            // TODO handle 404
            Method method = getMethod(getInterface(service), sr.getMethod(), sr.getArgs().size());
            if (method == null) {
                return wrap(sr.getSession(), ERROR, mapping + "/" + sr.getMethod() + " not found!");
            } else {
                Object[] args = sr.getArgs().values().toArray();
                Object result = super.doInvoke(service, method, args);
                return wrap(sr.getSession(), NORMAL, this.encodeResult(result));
            }
        }
    }

    private ServiceResponse wrap(String session, Status status, String result) {
        ServiceResponse sp = new ServiceResponse(session);
        return sp.setStatus(status).setResult(result);
    }

    private String encodeResult(Object result) {
        boolean isWriteNull = OpenxSetting.getTlSettingAsBoolean(OpenxSetting.OPENX_WRITE_NULL);
        return isWriteNull ? JSON.toJsonStringWithNull(result) : JSON.toJsonString(result);
    }
}